﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;

namespace ShevaEngine.Core.Modules.Graphics
{
    /// <summary>
    /// Vertex and index buffers manager.
    /// </summary>
    public class GraphicsBuffersManager
    {
        /// <summary>Buffers.</summary>
        private List<IGraphicsBuffers> Buffers;

        /// <summary>
        /// Constructor.
        /// </summary>
        public GraphicsBuffersManager()
        {
            this.Buffers = new List<IGraphicsBuffers>();
        }

        /// <summary>
        /// Methods return buffers id.
        /// </summary>
        /// <param name="vertices"></param>
        /// <param name="indices"></param>
        /// <returns></returns>
        public UInt16 AddBuffersData(DrawCall drawCall, List<IVertexType> vertices, List<Int32> indices)
        {
            IGraphicsBuffers graphicsBuffers = null;
            UInt16 buffersId = UInt16.MaxValue;

            for (int i = 0; i < this.Buffers.Count; i++)
                if (this.Buffers[i].CanAddData(drawCall, vertices[0].VertexDeclaration, indices))
                {
                    graphicsBuffers = this.Buffers[i];
                    buffersId = (UInt16)i;

                    break;
                }

            if (graphicsBuffers == null)
            {
                Type vertexType = vertices[0].GetType();
                Type graphicsBuffersGeneric = typeof(GraphicsBuffers<>);
                Type graphicsBuffersConcrete = graphicsBuffersGeneric.MakeGenericType(new Type[] { vertexType });

                graphicsBuffers = Activator.CreateInstance(graphicsBuffersConcrete, new object[] { vertices[0].VertexDeclaration }) as IGraphicsBuffers;

                buffersId = (UInt16)this.Buffers.Count;

                this.Buffers.Add(graphicsBuffers);
            }

            graphicsBuffers.AddData(drawCall, vertices, indices);

            return buffersId;
        }

        /// <summary>
        /// Methods return buffers id.
        /// </summary>
        /// <param name="vertices"></param>
        /// <param name="indices"></param>
        /// <returns></returns>
        public UInt16 AddBuffersData(DrawCall drawCall, VertexDeclaration vertexDeclaration, byte[] vertices, List<Int32> indices)
        {
            IGraphicsBuffers graphicsBuffers = null;
            UInt16 buffersId = UInt16.MaxValue;

            for (int i = 0; i < this.Buffers.Count; i++)
                if (this.Buffers[i].CanAddData(drawCall, vertexDeclaration, indices))
                {
                    graphicsBuffers = this.Buffers[i];
                    buffersId = (UInt16)i;

                    break;
                }

            if (graphicsBuffers == null)
            {
                Type vertexType = vertices[0].GetType();
                Type graphicsBuffersGeneric = typeof(GraphicsBuffers<>);
                Type graphicsBuffersConcrete = graphicsBuffersGeneric.MakeGenericType(new Type[] { vertexType });

                graphicsBuffers = Activator.CreateInstance(graphicsBuffersConcrete, new object[] { vertexDeclaration }) as IGraphicsBuffers;

                buffersId = (UInt16)this.Buffers.Count;

                this.Buffers.Add(graphicsBuffers);
            }

            graphicsBuffers.AddData(drawCall, vertices, indices);

            return buffersId;
        }

        /// <summary>
        /// Method creates buffers.
        /// </summary>
        public void CreateBuffers()
        {
            foreach (IGraphicsBuffers item in this.Buffers)
                item.CreateBuffers();
        }

        /// <summary>
        /// Method setups buffers.
        /// </summary>
        /// <param name="id"></param>
        public void SetupBuffers(UInt16 id)
        {
            ShevaEngine.Instance.GraphicsDevice.SetVertexBuffer(this.Buffers[(int)id].VBO);
            ShevaEngine.Instance.GraphicsDevice.Indices = this.Buffers[(int)id].IBO;
        }
    }    
}
